#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdbool.h>
#include<dirent.h>
#include<string.h>
#include<sys/stat.h>
#include<pwd.h>
#include<grp.h>
bool show_all=false;
bool show_list=false;
bool show_recursion=false;
void do_ls_r(char *pathname,int depth);
void do_ls(char *pathname);
int judge_dir(char *pathname);
void do_showlist(DIR *dp);
void mode_to_letters(int mode,char str[]);
char *uid_to_name(uid_t uid);
char *gid_to_name(gid_t gid);


int main(int argc,char *argv[])
{
	int opt;
	while((opt=getopt(argc,argv,"arl"))!=-1){
		switch(opt){
			case 'a':
				show_all=true;
				break;
			case 'r':
				show_recursion=true;
				break;
			case 'l':
				show_list=true;
				break;
			case '?':
				printf("unknow option :%c\n",optopt);
				exit(1);
		}
	}
	if(show_recursion){
		if(argc==optind)
		  do_ls_r(".",4);
		else{
			for(;optind<argc;optind++){
				if(judge_dir(argv[optind])){
					printf("%s:\n",argv[optind]);
				    do_ls_r(argv[optind],4);
				}
				else{
					printf("not a directory!\n");
					exit(1);
				}
			}
		}
	}
	else{
		if(argc==optind)
		  do_ls(".");
		else{
			for(;optind<argc;optind++){
				if(judge_dir(argv[optind])){
					printf("%s:\n",argv[optind]);
				    do_ls(argv[optind]);
				}
				else{
					printf("not a directory!\n");
					exit(1);
				}
			}
		}
	}

}

int judge_dir(char *pathname)
{
	struct stat statbuf;
	if((lstat(pathname,&statbuf))<0){
	  printf("error in lstat!\n");
	  exit(1);
	}
	if(S_ISDIR(statbuf.st_mode))
	  return 1;
	else
	  return -1;
}
void do_ls_r(char *pathname,int depth)
{
	DIR *dp;
	struct dirent *entry;
	struct stat statbuf;
	if((dp=opendir(pathname))==NULL){
		printf("can't open dir:%s\n",pathname);
		exit(1);
	}
	chdir(pathname);
	while((entry=readdir(dp))!=NULL){
		lstat(entry->d_name,&statbuf);
		if(S_ISDIR(statbuf.st_mode)){
			if(strcmp(".",entry->d_name)==0||strcmp("..",entry->d_name)==0)
			  continue;
			printf("%*s%s/\n",depth," ",entry->d_name);
			do_ls_r(entry->d_name,depth+4);
		}
		else
		  printf("%*s%s\n",depth," ",entry->d_name);
	}
	chdir("..");
	closedir(dp);

}
void do_ls(char *pathname)
{
	DIR *dp;
	struct dirent *entry;
	if((dp=opendir(pathname))==NULL){
			printf("can't open dir:%s\n",pathname);
			exit(1);
		}
	if(show_list){
		chdir(pathname);
	    do_showlist(dp);
	}
	else{
			while((entry=readdir(dp))!=NULL){
			if(!show_all)
			  if(*(entry->d_name)=='.')
				continue;
			printf("%s\n",entry->d_name);
		}
		closedir(dp);
	}
}
void do_showlist(DIR *dp)
{
	struct dirent *entry;
	struct stat statbuf;
	char l_mode[11];
	while((entry=readdir(dp))!=NULL){
		if((lstat(entry->d_name,&statbuf))<0){
			printf("error :in lstat\n");
			exit(1);
		}
		if(!show_all)
		  if(*(entry->d_name)=='.')
			continue;
		mode_to_letters(statbuf.st_mode,l_mode);
		printf("%s",l_mode);
		printf("%4d ",(int)statbuf.st_nlink);
		printf("%-8s ",uid_to_name(statbuf.st_uid));
        printf("%-8s ",gid_to_name(statbuf.st_gid));
		printf("%8ld ",(long)statbuf.st_size);
		printf("    %s ",entry->d_name);
		printf("\n");
	}
}
void mode_to_letters(int mode,char str[])
{
	strcpy(str,"----------");
	if(S_ISDIR(mode)) str[0]='d';
	if(S_ISCHR(mode)) str[0]='c';
	if(S_ISBLK(mode)) str[0]='b';

	if(mode&S_IRUSR)  str[1]='r';
	if(mode&S_IWUSR)  str[2]='w';
	if(mode&S_IXUSR)  str[3]='x';

	if(mode&S_IRGRP)  str[4]='r';
   	if(mode&S_IWGRP)  str[5]='w';
	if(mode&S_IXGRP)  str[6]='x';

	if(mode&S_IROTH)  str[7]='r';
	if(mode&S_IWOTH)  str[8]='w';
	if(mode&S_IXOTH)  str[9]='x';
}

char *uid_to_name(uid_t uid)
{
	struct passwd *getpwuid(),*pw_ptr;
	if((pw_ptr=getpwuid(uid))!=NULL)
	  return (pw_ptr->pw_name);
	else
	  return NULL;
}
char *gid_to_name(gid_t gid)
{
	struct group *getgrid,*grp_ptr;
	if((grp_ptr=getgrgid(gid))!=NULL)
	  return (grp_ptr->gr_name);
	else
	  return NULL;
}